package net.lengwang.iot.middleware.packet.request;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

import net.lengwang.iot.middleware.packet.ParsedPacket;

public class StatusReportPacketParser {

    public static ParsedPacket parsePacket(ParsedPacket parsedPacket) {

        parsedPacket.setStartFlag(parsedPacket.getModbusBytes(1, 2));
        parsedPacket.setLength(parsedPacket.getModbusByte(3));
        // 兼容多个版本
        if (parsedPacket.getLength().equals("31")) {
            return parsePacket31(parsedPacket);
        } else if (parsedPacket.getLength().equals("2C")) {
            return parsePacket2C(parsedPacket);
        } else {
            throw new IllegalArgumentException("不支持的数据包长度标识: " + parsedPacket.getLength());
        }
    }

    // | BE BE 2C 92 01 01 A2 59 11 11 11 11 17 09 11 15 13 00 10 68 00 01 00 01 00
    // 00 00 00 00 11 69 1C 74 09 09 75 70 00 33 46 6E 00 00 06 6F 00 00 00 00 EB EB
    // |
    // | --- |

    // | 起始位置 (10进制) | 内容 (16进制) | 含义 | 备注 |
    // | --- | --- | --- | --- |
    // | 01 | BE BE | 起始位 | 固定值 |
    // | 03 | 2C | 总长度 | 固定值 |
    // | 04 | 92 | 命令 | 固定值 |
    // | 05 | 01 | 协议版本 | |
    // | 06 | 01 A2 | 序列号 | 每次传输，此序列号递增，最大65535，达到最大值后从1开始。 |
    // | 08 | 59 | 设备类型 | 59：SGAla-网关 |
    // | 09 | 11 11 11 11 | GW ID | 网关编号 |
    // | 13 | 17 09 11 15 13 00 | GW传输时间 | BCD码，格式：“17年09月11日15时13分00秒”。 |
    // | 19 | 10 68 | GW电压 | U = (MSB*256+LSB)。其中U.bit15是状态位，U.bit14~bit0是数据位。
    // U.bit15=0，表示未连接充电器； U.bit15=1，表示已连接充电器； U.bit14~bit0表示电池电压，计算方法：电池电压 =
    // U.bit14~bit0/1000，单位：V。 |
    // | 21 | 00 01 | GW软件版本 | |
    // | 23 | 00 01 | 客户码 | 固定值 |
    // | 25 | 00 | 转发策略 | 0 = 转发接收到的所有数据包； 1 = 只转发绑定设备的数据包； other = 未定义； |
    // | 26 | 00 | RAM | |
    // | 27 | 00 00 00 | pflash已存数量 | |
    // | 30 | 11 | 负载长度 | 固定值 |
    // | 31 | 69 | 类型 | 固定值 |
    // | 32 | 1C | CSQ | 网络信号强度，取值范围：10到31；数值越大，信号越强 |
    // | 33 | 74 | 类型 | |
    // | 34 | 09 | Number | SG5：服务器端绑定Sensor设备的数量，最大值是64。SG6：网络类型 |
    // | 35 | 09 | Number | 网关端接收到Sensor设备的数量，最大值是64。 |
    // | 36 | 75 | 类型 | 固定值 |
    // | 37 | 70 00 33 46 | SIM No. | 若采集序列号是0，则： byte1：
    // 是否连接充电器（1:正在充电，2:充电完成，3:未接电池，4:未知错误）； byte2： 设备重启原因； byte3*256+byte4：
    // SIM卡MSIN的末尾4位； 若采集序列号不是0，则： byte1： 是否连接充电器；（1:正在充电，2:充电完成，3:未接电池，4:未知错误）
    // byte2*256*256+byte3*256+byte4： SIM卡MSIN的末尾7位 |
    // | 41 | 6E | 类型 | 固定值 |
    // | 42 | 00 00 06 | 上次成功传输数量 | 上次上传到平台的数据量 |
    // | 45 | 6F | 类型 | 固定值 |
    // | 46 | 00 00 | 保留位 | |
    // | 48 | 00 00 | CRC16 | 设为00 00可以屏蔽CRC16校验的功能。 |
    // | 50 | EB EB | 结束位 | 固定值 |
    public static ParsedPacket parsePacket2C(ParsedPacket parsedPacket) {
        // 起始位
        parsedPacket.setStartFlag(parsedPacket.getModbusBytes(1, 2));

        // 总长度
        parsedPacket.setLength(parsedPacket.getModbusByte(3));

        // 命令
        parsedPacket.setCommand(parsedPacket.getModbusByte(4));

        // 协议版本
        parsedPacket.setVersion(parsedPacket.getModbusByte(5));

        // 序列号
        parsedPacket.setSequenceNumber(parsedPacket.getModbusBytes(6, 2));

        // 设备类型
        parsedPacket.setDeviceType(parsedPacket.getModbusByte(8));

        // 网关ID
        parsedPacket.setGatewayId(parsedPacket.getModbusBytes(9, 4));

        // 网关传输时间
        String timeStr = parsedPacket.getModbusBytes(13, 6);
        parsedPacket.setTime(String.format("20%s-%s-%s %s:%s:%s",
                timeStr.substring(0, 2), timeStr.substring(2, 4), timeStr.substring(4, 6),
                timeStr.substring(6, 8), timeStr.substring(8, 10), timeStr.substring(10, 12)));

        // 网关电压
        int voltageRaw = parsedPacket.getModbusInt(19, 2);
        boolean isCharging = (voltageRaw & 0x8000) != 0;
        double voltage = (voltageRaw & 0x7FFF) / 1000.0;
        parsedPacket.setGatewayVoltage(voltage);
        parsedPacket.setGatewayCharging(isCharging);

        // 网关软件版本
        parsedPacket.setSoftwareMajorVersion(parsedPacket.getModbusInt(21, 2));

        // 客户码
        parsedPacket.setCustomerCode(parsedPacket.getModbusInt(23, 2));

        // 转发策略
        parsedPacket.setForwardingStrategy(parsedPacket.getModbusInt(25));

        // RAM
        parsedPacket.setRam(parsedPacket.getModbusInt(26));

        // pflash已存数量
        parsedPacket.setPflashStoredCount(parsedPacket.getModbusLong(27, 3));

        // 负载长度
        int payloadLength = parsedPacket.getModbusInt(30);

        // 类型（固定值69）
        int type1 = parsedPacket.getModbusInt(31);

        // CSQ
        parsedPacket.setCsq(parsedPacket.getModbusInt(32));

        // 类型
        int type2 = parsedPacket.getModbusInt(33);

        // Number (SG5: 服务器端绑定Sensor设备的数量 / SG6: 网络类型)
        int number1 = parsedPacket.getModbusInt(34);

        // Number (网关端接收到Sensor设备的数量)
        int number2 = parsedPacket.getModbusInt(35);

        // 类型（固定值75）
        int type3 = parsedPacket.getModbusInt(36);

        // SIM No.
        byte[] simNo = parsedPacket.getModbusBytes(37, 4).getBytes();
        boolean isCharging2 = simNo[0] == 1 || simNo[0] == 2;
        int restartReason = simNo[1];
        int simLastDigits = (simNo[2] & 0xFF) * 256 + (simNo[3] & 0xFF);
        parsedPacket.setGatewayCharging(isCharging2);
        parsedPacket.setRestartReason(restartReason);
        parsedPacket.setSimMsin(simLastDigits);

        // 类型（固定值6E）
        int type4 = parsedPacket.getModbusInt(41);

        // 上次成功传输数量
        int lastTransmissionCount = parsedPacket.getModbusInt(42, 3);

        // 类型（固定值6F）
        int type5 = parsedPacket.getModbusInt(45);

        // 保留位
        parsedPacket.setReserved(parsedPacket.getModbusBytes(46, 2));

        // CRC16
        parsedPacket.setCrc16(parsedPacket.getModbusBytes(48, 2));

        // 结束位
        parsedPacket.setEndFlag(parsedPacket.getModbusBytes(50, 2));

        // 设置命令名称
        parsedPacket.setCommandName("网关状态上报");

        return parsedPacket;
    }

    // 2.12.11网关状态数据上报示例：（网关→服务器）

    // | BE BE 31 92 03 00 01 6A 11 11 11 11 60 99 F5 80 10 68 00 01 00 01 00 01 00
    // 00 01 00 0A 0A 08 00 00 00 00 1C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    // 00 00 EB EB |
    // | --- |

    // | 起始位置 (10进制) | 内容 (16进制) | 含义 | 备注 |
    // | --- | --- | --- | --- |
    // | 01 | BE BE | 起始位 | 固定值 |
    // | 03 | 31 | 总长度 | 固定值 |
    // | 04 | 92 | 命令 | 固定值 |
    // | 05 | 03 | 协议版本 | 固定值 |
    // | 06 | 00 01 | 序列号 | 每次传输，此序列号递增，最大65535，达到最大值后从1开始。 |
    // | 08 | 6A | 设备类型 | 6A：SG6P |
    // | 09 | 11 11 11 11 | GW ID | 网关编号 |
    // | 13 | 60 99 F5 80 | GW上传时间 | UTC时间，2021-05-11 11:09:33 |
    // | 17 | 10 68 | GW电压 | U = (MSB*256+LSB)。其中U.bit15是状态位，U.bit14~bit0是数据位。
    // U.bit15=0，表示未连接充电器； U.bit15=1，表示已连接充电器； U.bit14~bit0表示电池电压，计算方法：电池电压 =
    // U.bit14~bit0/1000，单位：V。 |
    // | 19 | 00 01 | GW软件主版本 | |
    // | 21 | 00 01 | GW软件次版本 | |
    // | 23 | 00 01 | 客户码 | 固定值 |
    // | 25 | 00 00 | Debug | |
    // | 27 | 01 | 工作模式 | |
    // | 28 | 00 | 转发策略 | 0 = 转发接收到的所有数据包； 1 = 只转发绑定设备的数据包； other = 未定义； |
    // | 29 | 0A | 期望绑定 | |
    // | 30 | 0A | 实际绑定 | |
    // | 31 | 0A | 已收到SS数量 | |
    // | 32 | 08 | 网络类型 | 0 – no service 1 – GSM 2 – GPRS 3 – EGPRS (EDGE) 4 – WCDMA
    // 5 – HSDPA only(WCDMA) 6 – HSUPA only(WCDMA) 7 – HSPA (HSDPA and HSUPA, WCDMA)
    // 8 – LTE 9 – TDS-CDMA 10 – TDS-HSDPA only 11 – TDS- HSUPA only 12 – TDS- HSPA
    // (HSDPA and HSUPA) 13 – CDMA 14 – EVDO 15 – HYBRID (CDMA and EVDO) 16 –
    // 1XLTE(CDMA and LTE) 23 – eHRPD 24 – HYBRID(CDMA and eHRPD) |
    // | 33 | 00 00 00 00 | SIM MSIN | 转十进制 |
    // | 37 | 1C | CSQ | 网络信号强度，取值范围：10到31；数值越大，信号越强 |
    // | 38 | 00 | 误码率 | |
    // | 39 | 00 | RstSrc | 网关重启原因 |
    // | 40 | 00 | RAM | |
    // | 41 | 00 00 00 00 | pflash已存数量 | |
    // | 45 | 00 00 00 00 00 00 00 00 | 保留位 | |
    // | 53 | 00 00 | CRC16 | 设为00 00可以屏蔽CRC16校验的功能。 |
    // | 55 | EB EB | 结束位 | 固定值 |

    public static ParsedPacket parsePacket31(ParsedPacket parsedPacket) {
        parsedPacket.setStartFlag(parsedPacket.getModbusBytes(1, 2));
        parsedPacket.setLength(parsedPacket.getModbusByte(3));
        parsedPacket.setCommand(parsedPacket.getModbusByte(4));
        parsedPacket.setVersion(parsedPacket.getModbusByte(5));
        parsedPacket.setSequenceNumber(parsedPacket.getModbusBytes(6, 2));

        // 解析设备类型
        parsedPacket.setDeviceType(parsedPacket.getModbusByte(8));

        // 解析网关ID
        parsedPacket.setGatewayId(parsedPacket.getModbusBytes(9, 4));

        // 解析网关上传时间
        long timestamp = parsedPacket.getModbusLong(13);
        LocalDateTime uploadTime = LocalDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneOffset.UTC);
        parsedPacket.setGatewayUploadTime(uploadTime);

        // 解析网关电压
        int voltageRaw = parsedPacket.getModbusInt(17, 2);
        boolean isCharging = (voltageRaw & 0x8000) != 0;
        double voltage = (voltageRaw & 0x7FFF) / 1000.0;
        parsedPacket.setGatewayVoltage(voltage);
        parsedPacket.setGatewayCharging(isCharging);

        // 解析软件版本
        parsedPacket.setSoftwareMajorVersion(parsedPacket.getModbusInt(19, 2));
        parsedPacket.setSoftwareMinorVersion(parsedPacket.getModbusInt(21, 2));

        // 解析客户码
        parsedPacket.setCustomerCode(parsedPacket.getModbusInt(23, 2));

        // 解析Debug信息
        parsedPacket.setDebugInfo(parsedPacket.getModbusBytes(25, 2));

        // 解析工作模式
        parsedPacket.setWorkMode(parsedPacket.getModbusInt(27));

        // 解析转发策略
        parsedPacket.setForwardingStrategy(parsedPacket.getModbusInt(28));

        // 解析期望绑定、实际绑定和已收到SS数量
        parsedPacket.setExpectedBindings(parsedPacket.getModbusInt(29));
        parsedPacket.setActualBindings(parsedPacket.getModbusInt(30));
        parsedPacket.setReceivedSSCount(parsedPacket.getModbusInt(31));

        // 解析网络类型
        parsedPacket.setNetworkType(parsedPacket.getModbusInt(32));

        // 解析SIM MSIN
        parsedPacket.setSimMsin(parsedPacket.getModbusLong(33));

        // 解析CSQ（信号强度）
        parsedPacket.setCsq(parsedPacket.getModbusInt(37));

        // 解析误码率
        parsedPacket.setBitErrorRate(parsedPacket.getModbusInt(38));

        // 解析重启原因
        parsedPacket.setRestartReason(parsedPacket.getModbusInt(39));

        // 解析RAM
        parsedPacket.setRam(parsedPacket.getModbusInt(40));

        // 解析pflash已存数量
        parsedPacket.setPflashStoredCount(parsedPacket.getModbusLong(41));

        // 保留位
        parsedPacket.setReserved(parsedPacket.getModbusBytes(45, 8));

        // CRC16
        parsedPacket.setCrc16(parsedPacket.getModbusBytes(53, 2));

        // 结束位
        parsedPacket.setEndFlag(parsedPacket.getModbusBytes(55, 2));

        return parsedPacket;
    }
}
